<?php
/* Your initial Class declaration. This file's name must
   be "[class's name].module.php", or, in this case,
   Catlist.module.php
*/

global $IUsers_FloodCheck;

if(!class_exists('Antz')) return;

class IUsers extends CMSModule
{
public $hasLoggedPageRequest = false;
protected $log = null;
protected $ContentEditAlias = '';
private $ThrowConfigExceptions = false;// handy while developing
protected $IUsers_Config = array();


function HasAdmin(){return true;}
function GetAdminSection() {return 'usersgroups';}
function VisibleToAdminUser() {
    $vis = false;
    if($this->CheckPermission($this->GetName().' Users')) $vis = true;
    if($this->CheckPermission($this->GetName().' Groups')) $vis = true;
    if($this->CheckPermission($this->GetName().' Places')) $vis = true;
    if($this->CheckPermission($this->GetName().' Config')) $vis = true;
    return $vis;
}
function GetName(){return 'IUsers';}
function GetFriendlyName(){return $this->Lang('friendlyname');}
function GetVersion(){return '0.9.2';}
function MinimumCMSVersion(){return '1.6.1';}
function IsPluginModule(){return true;}
function GetDependencies(){return array('Antz'=>'1.0.0');}
function GetHelp(){return file_get_contents($this->config['root_path'].'/modules/IUsers/docs/help.html');}
function GetChangeLog(){return nl2br(file_get_contents($this->config['root_path'].'/modules/IUsers/docs/changelog-0.8.0.txt'));}

/**
 * API method to check if user belongs to a group or any of a number of groups
 * Accepts:
 * group key as string or group keys as array of group strings
 * optional userid as int, if not supplied, takes from $USER->userid
 */
public function isMemberOfGroup($groupKey, $userid=''){
	$USER = Antz::registry('user');
	$DB = Antz::registry('db');
	$userid = (int) $userid;

	if(is_array($groupKey)){
		foreach($groupKey as $k=>$group){
			if($this->isMemberOfGroup($group, $userid)) return true;
		};
		// not found
		return false;
	};

	// testing for a single group as string
	$groupKey = preg_replace('/[^a-zA-Z0-9\-_]/', '', $groupKey);
	//echo "SELECT COUNT(*) FROM cms_iusers_to_groups WHERE user_id = '{$userid}' AND group_key = '{$groupKey}'";
	if($userid==0) $userid = (int) $USER->userid;
	if($DB->countRows(cms_db_prefix().'iusers_to_groups', "user_id = '{$userid}' AND group_key = '{$groupKey}'")>0) return true;
	else return false;
}


/**
 * API method to load user data
 * Returns data from iusers tab combined with data from other modules
 * Accepts: $userid (int)
 * Returns: array
 */
public function getUserData($userid){
  $DB = Antz::registry('db');
  $userid = (int) $userid;
  $uData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers WHERE id = '{$userid}'");
  $newData = Antz::Hookup('IUsers_GetUserData', array('userid'=>$userid, 'uData'=>$uData));
  $uData = $newData['params']['uData'];
  unset($newData);
  return $uData;
}

/**
 *  Allows any code to register a new user in the database
 *  Accepts an array of user data, with keys "username" and "email" being mandatory, "password" is optional
 *  All values must be unencrypted
 *  Returns the new user id on success or an array on error:
 *  array(
 *      'error' => true,
 *      'errors' => array('Message 1', 'Message 2', 'etc')
 *  )
 */
public function RegisterUser($uData){
    $DB = Antz::registry('db');
    $CRYPT = Antz::registry('crypt');

    $error = false;
    $errors = array();

    // check a few things first
    if(!isset($uData['username'])){
        $error = true;
        $errors[] = $this->Lang('invalid_username');
    }

    if(!isset($uData['email'])){
        $error = true;
        $errors[] = $this->Lang('invalid_email');
    }


    if(!Antz_Filter::checkEmail($uData['email'])){
        $error = true;
        $errors[] = $this->Lang('invalid_email');
    }

    if($DB->countRows(cms_db_prefix().'iusers', "username = '{$username}'")>0){
        $error = true;
        $errors[] = $this->Lang('username_already_registered');
    }

    $emailMD5 = md5(strtolower($uData['email']));

    if($DB->countRows(cms_db_prefix().'iusers', "email_md5 = '{$emailMD5}'")>0){
        $error = true;
        $errors[] = $this->Lang('email_already_registered');
    }

    if($error){
        return array('error'=>true, 'errors'=>$errors);
    }

    $uData['email_crypt'] = isset($uData['email']) ? $CRYPT->crypt($uData['email']) : '';
    $uData['email_md5'] = $emailMD5;
    $uData['pass'] = isset($uData['password']) ? $CRYPT->crypt($uData['password']) : '';

    // create a compliant array to insert
    $newUData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers LIMIT 1");

    unset($newUData['id']);

    foreach($newUData as $k=>$v){
        $newUData[$k] = isset($uData[$k]) ? $uData[$k] : '';
    }
    
    $userid = $DB->insert(cms_db_prefix().'iusers', $newUData);
    $newUData['id'] = $userid;

    // groups
    if(!is_array($uData['groups'])){
        $uData['groups'] = explode(',', $uData['groups']);
    };
    foreach($uData['groups'] as $k=>$groupKey){
        $groupKey = preg_replace('/[^a-zA-Z0-9\-_]/', '', $groupKey);
        if($DB->countRows(cms_db_prefix().'iusers_groups', "keyname = '{$groupKey}'")==0){
            unset($uData['groups'][$k]);
        };
    };
    if(count($uData['groups'])==0){
        $uData['groups'] = explode(',', $this->GetConfig('default_groups_for_self_registration'));
    };
    foreach($uData['groups'] as $groupKey){
        $dbParams = array(
            'user_id' => $userid,
            'group_key' => $groupKey
        );
        $DB->insert(cms_db_prefix().'iusers_to_groups', $dbParams);
    };
    
    $hookParams = array('user_data' => $newUData);
	$newParams = Antz::Hookup('IUsers_RegisterProcess', $hookParams);
	$hookParams = $newParams['params'];
	unset($newParams);
    
    return $userid;
}




/**
 * Allows any code to log a user in by passing either userid, username, email or user data in an array
 */
public function Login($data){
    $USER = Antz::registry('user');
    $DB = Antz::registry('db');


    if(is_array($data)){
        return $USER->login($data);
    }
    if(Antz_Filter::checkEmail($data)){
        $emailMD5 = md5(strtolower($data));
        $uData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers WHERE email_md5 = '{$emailMD5}'");
        return $USER->login($uData);
    }
    if(intval($data) === $data && $data > 0){
        $uData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers WHERE id = '{$data}'");
        return $USER->login($uData);
    }
    $data = preg_replace('/[^a-zA-Z0-9\-_]/', '', $data);
    $uData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers WHERE username = '{$data}'");
    if(is_array($uData)){
        return $USER->login($uData);
    }

    // failed to login :(
    return false;

}



public function __construct(){
    parent::CMSModule();
    global $gCms;

    if(!class_exists('Antz')){
        //throw new Exception('Tried to instantiate module: '.$this->GetName().', but required module "Antz" is not available.');
        return;
    }
    $Antz = Antz::registry('Antz');

    if(!is_object($Antz) || !($Antz instanceof Antz)) {
        //throw new Exception('Tried to instantiate module: '.$this->GetName().', but required module "Antz" is not available.');
        return;
    };

    // automatically load our configuration settings once only
    if(count($this->IUsers_Config) == 0) $this->LoadConfig();
    if(count($this->IUsers_Config) == 0){
        // probably not installed, can't proceed
        return;
    };

	$dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
	$this->dirname = $dirname;

    $USER = Antz::registry('user');
    $DB = Antz::registry('db');

    // check for dos attacks/flooding
    global $IUsers_FloodCheck;
    if($IUsers_FloodCheck !== 'served'){
        $IUsers_FloodCheck = 'served';
        if(count($USER->floodCheck)==0) $USER->floodCheck = array('numRequests'=>0, 'lastCheck'=>time());
        $USER->floodCheck['numRequests']++;
        if($USER->floodCheck['lastCheck'] < (time()-$this->GetConfig('dos_frequency'))){
            // reset the records every x seconds
            $USER->floodCheck['numRequests'] = 0;
            $USER->floodCheck['lastCheck'] = time();
        };
        if($USER->floodCheck['numRequests'] > $this->GetConfig('dos_max')){
            // flooding occurs!
            while(ob_get_level()>0) ob_end_clean();
            header('Status: '.$this->GetConfig('dos_status'));
            die($this->ProcessTemplate('dos_response.php'));
        };
    };

    if(!$USER->isLoggedIn()){
        // check if they have an auto-login cookie
        if(isset($_COOKIE[$this->GetConfig('cookie_name').'_userid']) && $_COOKIE[$this->GetConfig('cookie_name').'_userid']>0){
            // they have a cookie set, lets see if it is valid
            $userid = (int) $_COOKIE[$this->GetConfig('cookie_name').'_userid'];
            $hashCookie = preg_replace('/[^a-zA-Z0-9]/', '', $_COOKIE[$this->GetConfig('cookie_name').'_hash']);
            if($DB->countRows(cms_db_prefix().'iusers', "id = '{$userid}' AND cookie_hash = '{$hashCookie}'")>0){
                // valid returning user
                $uData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers WHERE id = '{$userid}'");
                $USER->login($uData);
            }else{
                // they have a cookie, but not the right authorization, maybe a security risk?
                $CRYPT = Antz::registry('crypt');
                try{
                    $uData = $DB->fetchRow("SELECT * FROM {$this->config['db_prefix']}iusers WHERE id = '{$userid}'");
                    $uData['email'] = $CRYPT->decrypt($uData['email_crypt']);
                    throw new exception('A user has a cookie set, but the cookie hash is not valid. Maybe a hack attempt? '."\nThey provided a userid corresponding to the following result set: \n".print_r($uData, true));
                }catch (exception $e){
                    $msg = $e->getMessage()."\n\nUrl: ".THIS_PAGE_URL."\n\n".print_r($_SERVER, true)."\n\n".print_r($_SESSION, true)."\n\n".print_r($_COOKIE, true)."\n\n".print_r($_POST, true);
                    $subject = $this->Lang('invalid_cookie_set_admin_notice');
                    $toFrom = array(
                        'toEmail' => $this->GetConfig('admin_notification_alerts'),
                        'toName'=>''
                    );
                    Antz_Email::sendRaw($subject, $msg, $toFrom);
                };
                // remove these cookies, since they are such a nuisance...
                setcookie ($this->GetConfig('cookie_name').'_userid', "", (time() - (60*60*24*100)));
                setcookie ($this->GetConfig('cookie_name').'_hash', "", (time() - (60*60*24*100)));
                //Antz::addError('LOL!! Your cookies were corrupt!!');
            };
        };
    }





    // only log once per page
    if(!$this->hasLoggedPageRequest){

        $USER = Antz::registry('user');

        $this->hasLoggedPageRequest = true;

        $sId = session_id();

        $serverData = '';
        $sessionData = '';
        $postData = '';
        $getData = '';

        // if configured in control panel, you can log every page's session object
        if($this->GetConfig('monitor_session_data')) $sessionData = serialize($_SESSION);

        if($DB->countRows(cms_db_prefix().'iusers_history', "session_id = '{$sId}'") == 0) $sessionData = serialize($_SESSION);

        if($this->GetConfig('monitor_server_data')) $serverData = serialize($_SERVER);

        if($this->GetConfig('monitor_post_data')) $postData = serialize($_POST);

        if($this->GetConfig('monitor_get_data')) $getData = serialize($_GET);




        $uHistory = array(
            'userid' => $USER->userid,
            'username' => $USER->username,
            'tstamp' => time(),
            'session_id' => session_id(),
            'url' => THIS_PAGE_URL,
            'session_data' => $sessionData,
            'server_data' => $serverData,
            'get_data' => $getData,
            'post_data' => $postData
        );

        $DB->insert(cms_db_prefix().'iusers_history', $uHistory);

    }



    // register the checkperms block function for smarty
    $this->smarty->register_block('showif', array($this, 'showif_block'));
    $this->smarty->register_block('showto', array($this, 'showif_block'));
    $this->smarty->register_block('hidefrom', array($this, 'hidefrom_block'));

    Antz::register('IUsers', $this);

    $this->SetSmartyVars();

}



public function SetSmartyVars(){
    // now we assign some variables for use in smarty
    $USER = Antz::registry('user');
    $iusers = array(
        'username' => $USER->username,
        'userid' => $USER->userid,
        'isLoggedIn' => $USER->isLoggedIn(),
        'country' => $USER->country
    );
    $this->smarty->assign('IUsers', $iusers);
    $this->smarty->assign('IUSER', $USER);
}

public function ParseMenu($nodelist){

    //echo '<pre>';var_dump($nodelist);exit;
    $USER = Antz::registry('user');
    $DB = Antz::registry('db');
    $logoutId = $this->GetConfig('logout_id');
    $loginId = $this->GetConfig('login_id');
    $regId = $this->GetConfig('register_id');


    foreach($nodelist as $k=>$node){
        //echo 'page: '.$node->id.' ( '.$node->menutext.' )<br />';

        if($k==0) $prevdepth = $node->prevdepth;

        if($node->id == $loginId || $node->id == $regId){
            if($USER->isLoggedIn()){
                unset($nodelist[$k]);
                continue;
            };
        }else if($node->id == $logoutId){
            if(!$USER->isLoggedIn()){
                unset($nodelist[$k]);
                continue;
            };
        };

        if($this->GetConfig('show_unpermitted_menu_items')==1){
            continue;
        };

        $pagesToGroups = $this->config['db_prefix'].'iusers_pages_to_groups';
        $usersToGroups = $this->config['db_prefix'].'iusers_to_groups';

        $query = "SELECT
          {$this->config['db_prefix']}iusers_pages_to_groups.page_id as page_id
          FROM
          {$pagesToGroups} JOIN {$usersToGroups}
          ON
          {$pagesToGroups}.group_key = {$usersToGroups}.group_key
          WHERE
          {$pagesToGroups}.page_id = '{$node->id}'
          AND
          {$usersToGroups}.user_id = '{$USER->userid}'";
          $row = $DB->fetchRow($query);

          //echo $query.'<br />';

          if(is_array($row) && count($row)>0){
              // permitted to view
              $node->prevdepth = $prevdepth;
              $prevdepth = $node->depth;
              continue;
          }else{
              // not permitted

              // carry over the prev depth
              if($node->prevdepth < $node->depth) $prevdepth = $node->prevdepth;
              else $prevdepth = $node->depth;
              $node->prevdepth = $prevdepth;
              unset($nodelist[$k]);
          };
    };

    return array_regenerate_keys($nodelist);

}

public function ContentReadyForEdit($contentObj){
    if($this->ContentEditAlias == '') $this->ContentEditAlias = $contentObj->Alias();
}

public function showif_block($params, $content, &$smarty){
    $USER=Antz::registry('user');
    $DB = Antz::registry('db');
    global $gCms;

    if (!array_key_exists('groups', $params)) {
        $this->smarty->trigger_error("assign: missing 'groups' parameter");
        return;
    };

    $groups = explode(',', $params['groups']);
    foreach($groups as $k=>$v){
        $groups[$k] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $v);
        if($groups[$k]=='') unset($groups[$k]);
    };

    if(count($groups)==0){
        $this->smarty->trigger_error('At least one group must be defined in the groups attribute');
        return;
    };

    foreach($groups as $k=>$v){
        $where = "group_key = '{$v}' AND user_id = '{$USER->userid}'";
        if($DB->countRows(cms_db_prefix().'iusers_to_groups', $where) > 0) return $content;
    };
    // not permitted
    return '';

}



public function hidefrom_block($params, $content, &$smarty){
    $USER=Antz::registry('user');
    $DB = Antz::registry('db');
    global $gCms;

    if (!array_key_exists('groups', $params)) {
        $this->smarty->trigger_error("assign: missing 'groups' parameter");
        return;
    };

    $groups = explode(',', $params['groups']);
    foreach($groups as $k=>$v){
        $groups[$k] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $v);
        if($groups[$k]=='') unset($groups[$k]);
    };

    if(count($groups)==0){
        $this->smarty->trigger_error('At least one group must be defined in the groups attribute');
        return;
    };

    foreach($groups as $k=>$v){
        $where = "group_key = '{$v}' AND user_id = '{$USER->userid}'";
        if($DB->countRows(cms_db_prefix().'iusers_to_groups', $where) > 0) return '';
    };

    // permitted
    return $content;

}




function GetContentFields($contentObj){
    $DB = Antz::registry('db');
    //$DB->debug(true);
    //$DB->showErrors(true);
    $pageid = (int) $contentObj->Id();
    if($pageid > -1){
        // page exists, get the groups
        $currentGroups = $DB->fetchAll("SELECT * FROM ".cms_db_prefix()."iusers_pages_to_groups WHERE page_id = '{$pageid}'");
        $cg = array();
        foreach($currentGroups as $k=>$v){
            $cg[$k] = $v['group_key'];
        };
    }else{
        $cg = explode(',', $this->GetConfig('default_groups_for_new_pages'));
    };
    $accessGroups = $DB->fetchAll("SELECT * FROM {$this->config['db_prefix']}iusers_groups");
    $opts = array();
    foreach($accessGroups as $k=>$v){
        $selected = (in_array($v['keyname'], $cg)) ? 'selected="selected"' : '';
        $opts[] = '<option value="'.$v['keyname'].'" '.$selected.'>'.$v['title'].'</option>';
    };
    return array(
        array($this->Lang('access_groups'), '<select name="access_groups[]" multiple="multiple">'.implode("\n", $opts).'</select>'),
        array($this->Lang('recurse_into_subpages'), '<input type="checkbox" name="ag_recursive" value="1">')
    );
}

function ContentEditPre($contentObj){
}

function ContentEditPost($contentObj){


    $DB = Antz::registry('db');
    $INPUT = Antz::registry('input');
    $pageid = (int) $contentObj->Id();
    $accessGroups = $INPUT->getPostValue('access_groups', 1000, array('public'));

    // get rid of the rubbish
    foreach($accessGroups as $k=>$accessGroup){
        $accessGroups[$k] = preg_replace('/[^a-zA-Z0-9\-_]/', '', $accessGroup);
        if($DB->countRows(cms_db_prefix().'iusers_groups', "keyname = '{$accessGroups[$k]}'")==0) unset($accessGroups[$k]);
    }

    // prevent removing all permissions from a page, although the select menu doesn't allow it anyway
    if(count($accessGroups)==0) return;

    if(post('ag_recursive', 0)==1){
        // set permissions recursively
        $this->SetAccessGroupsRecursively($accessGroups, $pageid);

    }else{
        // set permissions on this page only
        $DB->delete(cms_db_prefix().'iusers_pages_to_groups', "page_id = '{$pageid}'");
        
        foreach($accessGroups as $k=>$v){
            $DB->insert(cms_db_prefix().'iusers_pages_to_groups', array('page_id'=>$pageid, 'group_key'=>$v));
        }
    };

/*
    $fields = array(
        'login_url',
        'logout_url',
        'email_verification_url',
        'profile_url',
        'register_url',
        'change_country_url'
    );
    if($this->ContentEditAlias != ''){
        // update the alias
        //echo 'Changing from '.$this->ContentEditAlias.' to '.$contentObj->Alias().'<br />';
        foreach($fields as $k=>$v){
            if($this->GetConfig($v)==$this->ContentEditAlias){
                $DB->update(cms_db_prefix().'iusers_config', array('v'=>$contentObj->Alias()), "k = '{$v}'");
                $this->ContentEditAlias = '';
            };
        };

    };
*/
}

function SetAccessGroupsRecursively($accessGroups, $pageid){
    $DB = Antz::registry('db');
    $DB->delete(cms_db_prefix().'iusers_pages_to_groups', "page_id = '{$pageid}'");
    foreach($accessGroups as $k=>$v){
        $accessGroup = preg_replace('/[^a-zA-Z0-9]/', '', $v);
        $DB->insert(cms_db_prefix().'iusers_pages_to_groups', array('page_id'=>$pageid, 'group_key'=>$accessGroup));
    };
    $subPages = $this->GetSubPages($pageid, array('content_id'));
    foreach($subPages as $k=>$v){
        $this->SetAccessGroupsRecursively($accessGroups, $v['content_id']);
    };
}
function GetSubPages($parentId, $fields){
    $DB = Antz::registry('db');
    $fields = implode(',', $fields);
    return $DB->fetchAll("SELECT {$fields} FROM {$this->config['db_prefix']}content WHERE parent_id = '{$parentId}' ORDER BY item_order");
}

function InstallPostMessage()
{
    $DB = Antz::registry('db');
    return $this->Lang('installation_success');

}


function UninstallPreMessage(){
    $DB = Antz::registry('db');
    // hehe, wanna see some really coole code:

    return $this->Lang('pages_to_remove',
    '"'.$DB->oneValue(cms_db_prefix().'content', 'menu_text', "content_id = '".$this->GetConfig('register_id')."'").'"'.', '.
    '"'.$DB->oneValue(cms_db_prefix().'content', 'menu_text', "content_id = '".$this->GetConfig('login_id')."'").'"'.', '.
    '"'.$DB->oneValue(cms_db_prefix().'content', 'menu_text', "content_id = '".$this->GetConfig('logout_id')."'").'"'.', '.
    '"'.$DB->oneValue(cms_db_prefix().'content', 'menu_text', "content_id = '".$this->GetConfig('profile_id')."'").'"'.', '.
    '"'.$DB->oneValue(cms_db_prefix().'content', 'menu_text', "content_id = '".$this->GetConfig('tnc_id')."'").'"'.' - OK? ');
}

function UninstallPostMessage(){
    return $this->GetName().$this->Lang('successfully_uninstalled');
}


function MergeLang($thelang){
    // get our language as array
    global $gCms;

    if($this->curlang!='') $ourlang = $this->curlang;
    else if(isset($gCms->current_language)) $ourlang = $gCms->current_language;
	else $ourlang = $this->DefaultLanguage();
	//	else $ourlang = $USER->getLang();
	$lang = array();
	if(file_exists($this->dirname.'/lang/ext/'.$ourlang.'.php')) include($this->dirname.'/lang/ext/'.$ourlang.'.php');
	else include($this->dirname.'/lang/en_US.php');
	return array_merge($thelang, $lang);
}


function DoAction($action, $id, $params, $returnid=-1){
    $DB = Antz::registry('db');


    // get hold of our objects
    $SMARTY = $this->smarty;
    $USER = Antz::registry('user');
    $CRYPT = Antz::registry('crypt');
    $Antz = Antz::registry('Antz');
    $this->IUsers2SMF = $this->GetModuleInstance('IUsers2SMF');
    global $gCms;
    $rootPath = str_replace(DIRECTORY_SEPARATOR, '/', $gCms->config['root_path']);

	// load our language array and give it to smarty
	$ourlang = array();
	$ourlang = $this->MergeLang($ourlang);
	$this->smarty->assign('lang', $ourlang);

    //$contentops = $gCms->GetContentOperations();
    //$h = $contentops->getAllContentAsHierarchy(false);
    //echo '<pre>';var_dump($h);exit;

    //$USER->logout();
    //echo $USER->userid;exit;

    // we can set any usernames that are disallowed - must be lowercase
    $DISALLOWED_USERNAMES = array(
        'admin',
        'guest',
        'antz',
        'oi_antz',
        'oi-antz'
    );

    $emailVerificationUrl = $Antz->getUrlById($this->GetConfig('email_verification_id'));


    if($action == 'decrypt'){
        echo $CRYPT->decrypt($params['value']);
        return;
    }elseif($action=='country_title'){
        $id = preg_replace('/[^a-zA-Z0-9]/', '', $params['id']);
        echo $DB->oneValue(cms_db_prefix().'iusers_countries', 'title', "id = '{$id}'");
        return;
    }else if($action=='city_title'){
        $id = (int) $params['id'];
        echo $DB->oneValue(cms_db_prefix().'iusers_cities', 'title', "id = '{$id}'");
        return;


    /**
     *  CHECK PERMISSIONS, REDIRECT ON FAIL
     */
    }else if($action=='checkperms_redirect'){
        // check if they have permission to view this page, if not, set last page and redirect to the login page
        $Antz = Antz::registry('Antz');
        $loginUrl = $Antz->GetUrlById($this->GetConfig('login_id'));
        $logoutUrl = $Antz->GetUrlById($this->GetConfig('logout_id'));

        if(THIS_PAGE_URL == $this->config['root_url']){
            // always permitted to view the homepage
            return;
        };
        if(strpos(THIS_PAGE_URL, $logoutUrl)!==false){
            // always permitted to view the logout page
            return;
        };
        if(strpos(THIS_PAGE_URL, $loginUrl)!==false){
            // always permitted to view the login page
            return;
        };

        // for module ELetters
        if($ELetters = $this->GetModuleInstance('ELetters')){
            // allow access to the page if a newsletter is being sent
            if($ELetters->isSending()) return;
        };

        if(isset($USER->redirhash) && $CRYPT->decrypt(get('redirhash')) == $USER->redirhash){
            // this is definitely the login page, we must allow them to see it even if the system is mis-configured
            unset($USER->redirhash);
            return;

        }else{
            // this is probably not the login page
            $pagesToGroups = $this->config['db_prefix'].'iusers_pages_to_groups';
            $usersToGroups = $this->config['db_prefix'].'iusers_to_groups';
            $query = "SELECT
              {$this->config['db_prefix']}iusers_pages_to_groups.page_id as page_id
              FROM
              {$pagesToGroups} JOIN {$usersToGroups}
              ON
              {$pagesToGroups}.group_key = {$usersToGroups}.group_key
              WHERE
              {$pagesToGroups}.page_id = '{$gCms->variables['content_id']}'
              AND
              {$usersToGroups}.user_id = '{$USER->userid}'";
              $row = $DB->fetchRow($query);

              if(is_array($row) && count($row)>0){
                  // permitted to view
                  return;

              }else{
                  // not permitted, redirect to the login page

                  //echo $query;exit;

                  Antz::setLastPage();
                  $hash = rand(0, 9999);
                  $USER->redirhash = $hash;
                  $loginUrl = $Antz->AddParamsToUrl($loginUrl, array('redirhash'=>$CRYPT->crypt($hash)));
                  if($USER->isLoggedIn()) {

                      Antz::addError($this->Lang('checkperms_redirect_error', $USER->username));
                  }else{
                      //echo THIS_PAGE_URL.' '.$logoutUrl.'<br />';
                      Antz::addError($this->Lang('must_be_logged_in_for_page'));
                  };
                  Antz::redir($loginUrl);

              };

        };

    /**
     *  SHOW THE FLAGS FOR CHANGING COUNTRY
     */
    }else if($action == 'flags'){
         echo 'Changing country is not available until CMS Made Simple supports languages';
         return;

         $flags = $DB->fetchAll("SELECT id, title, filename FROM {$this->config['db_prefix']}iusers_countries WHERE show_flag = 1");
         if(!$flags) $flags = array();
         foreach($flags as $k=>$v){
             $flags[$k]['image'] = $this->config['root_url'].'/modules/'.$this->GetName().'/images/flags/'.$v['filename'];
             $urlParams = array('country'=>$v['id'], 'return_url'=>THIS_PAGE_URL);
             $url = $Antz->GetUrlByAlias($this->GetConfig('change_country_url'));
             $flags[$k]['url'] = $Antz->AddParamsToUrl($url, $urlParams);
             if($v['id']==$USER->country) $flags[$k]['selected'] = true;
             else $flags[$k]['selected'] = false;
         };
         $this->smarty->assign('IUsers_Flags', $flags);
         echo $this->ProcessTemplate('flags.php');


    /**
     *  ALLOW A USER TO CHANGE THEIR COUNTRY
     */
    }else if($action == 'change_country'){
        $country = preg_replace('/[^a-zA-Z0-9]/', '', get('country'));
        $url = get('return_url');
        if(strpos($url, 'http')===false){
            $url = Antz::getLastPage();
        };
        if($DB->countRows(cms_db_prefix().'iusers_countries', "id = '{$country}'")==0){
            Antz::addError('Invalid country');
            Antz::redir($url);
        }else{
            $USER->country = $country;
            Antz::redir($url);
        };

    /**
     *  LOGOUT
     */
    }else if($action=='logout'){
         $USER->logout();
         setcookie ($this->GetConfig('cookie_name').'_userid', "", time()-60*60*24*100);
         setcookie ($this->GetConfig('cookie_name').'_hash', "", time()-60*60*24*100);

         Antz::addSuccess('You have successfully logged out');

	if(get('return_url')!='') $returnUrl = get('return_url');
        else $returnUrl = Antz::getLastPage();

        // allow other modules to act on logout action
        Antz::Hookup('IUsers_LogoutProcess', array());

        // SMF integration
        if(is_object($this->IUsers2SMF) && $this->IUsers2SMF instanceof IUsers2SMF){
            $this->IUsers2SMF->logout($returnUrl);
        };// end SMF integration

        // only gets here if smf not enabled
        Antz::redir($returnUrl);

    /**
     *  DEFAULT
     */
    }else if($action=='default'){

    /**
     *  LOGIN
     */
    }else if($action=='login'){
        include('actions/login.php');
        return;

    /**
     *  REGISTER
     */
    }else if($action=='register'){
        // configuration may allow admin to register accounts without a name
        $insistFirstName = $this->GetConfig('fe_insist_fname');
        $insistLastName = $this->GetConfig('fe_insist_lname');

        include('actions/register.php');


    /**
     *  PROFILE
     */
    }else if($action=='profile'){
        include('actions/profile.php');

     /**
     *  VERIFY EMAIL ADDRESS
     */
    }else if($action=='verify_email'){
        include('actions/verify_email.php');




     /**
     *  LOST PASSWORD RETRIEVAL
     */
    }else if($action=='lost_password'){
        include('actions/lost_password.php');














    /**
     *  DEFAULT ADMIN
     */









    }else if($action=='defaultadmin'){
        // don't allow access if they aren't authorized
        if(!$this->VisibleToAdminUser()){
            echo ($this->Lang('insufficient_permissions'));
            return;
        };
        /*
        $dirname = dirname(__FILE__);
        $dirname = str_replace(DIRECTORY_SEPARATOR, '/', $dirname);
        $filename = $dirname.'/install/cities_optimized/cities_optimized.txt';
        $DB->query("TRUNCATE {$this->config['db_prefix']}iusers_cities");
        $DB->query("LOAD DATA INFILE '{$filename}' INTO TABLE {$this->config['db_prefix']}iusers_cities");

        die('done');
    */
        // some objects don't exist yet in the admin section
        Antz::register('smarty', $this->smarty);

        // we can't be logged into the forums when we try to create 
        if(isset($gCms->modules['IUsers2SMF']) && isset($_COOKIE[$gCms->modules['IUsers2SMF']['object']->GetConfig('smf_cookie')])){
            
            $gCms->modules['IUsers2SMF']['object']->logout(THIS_PAGE_URL);
        };


        // enable us to insert error messages on the page
        echo '<link href="'.$this->config['root_url'].'/modules/Antz/css/forms.css" rel="stylesheet" media="all" />';
        echo '<script src="'.$this->config['root_url'].'/modules/'.$this->GetName().'/js/admin.js" type="text/javascript"></script>';
        echo '<script src="'.$this->config['root_url'].'/modules/'.$this->GetName().'/js/AntzBase.js" type="text/javascript"></script>';
        echo '<script src="'.$this->config['root_url'].'/modules/'.$this->GetName().'/js/places.js" type="text/javascript"></script>';

        // configuration may allow admin to register accounts without a name
        $insistFirstName = $this->GetConfig('be_insist_fname');
        $insistLastName = $this->GetConfig('be_insist_lname');

        // include our stylesheet
        echo '<link href="'.$this->config['root_url'].'/modules/'.$this->GetName().'/css/backend.css" rel="stylesheet" media="all" />';

        if(!empty($params['active_tab'])) $selectedTab = $params['active_tab'];
        else $selectedTab = 'view';

        $tabs = array();

        if($this->CheckPermission($this->GetName().' Users')){
            // tabs for managing users
            $tabs['view'] = $this->Lang('view_tab');
            $tabs['new'] = $this->Lang('new_tab');
            $tabs['edit'] = $this->Lang('edit_tab');
        };
        if($this->CheckPermission($this->GetName().' Groups')){
            $tabs['groups'] = $this->Lang('groups_tab');
        };
        if($this->CheckPermission($this->GetName().' Places')){
            $tabs['places'] = $this->Lang('places_tab');
        };
        if($this->CheckPermission($this->GetName().' Config')){
            $tabs['config'] = $this->Lang('config_tab');
        };


        $actionUrls = array();

        // calculate the urls to get to each tab
        foreach($tabs as $tab=>$title){
            $params['active_tab'] = $tab;
            $actionUrls[$tab] = $this->GetUrl($params, $id, $this->GetName(), 'defaultadmin');
        };

        $SMARTY->assign('actionUrls', $actionUrls);

        $adminTabs = array();
        foreach($tabs as $k=>$title){
            if($k==$selectedTab) $class = 'selected';
            else $class = '';
            $adminTabs[] = array(
                'key'=>$k,
                'title' => $title,
                'url' => $actionUrls[$k],
                'class' => $class
            );
        };
        $this->smarty->assign('adminTabs', $adminTabs);

        echo $this->processTemplate('admin.tabs.php');

        echo '<div id="admin-content">';
        include($rootPath.'/modules/'.$this->GetName().'/tabs/admin.'.$selectedTab.'.php');
        echo '</div>';

/*
        // perform actions depending on the tab being viewed
        include('actions/admin.'.$selectedTab.'.php');


        // set up the tab headers
        echo $this->StartTabHeaders();
        foreach($tabs as $tab=>$title){
            echo $this->SetTabHeader($tab, $title, $selectedTab == $tab ? true : false);
        };
        echo $this->EndTabHeaders();

        // populate the tab contents
        echo $this->StartTabContent();
        foreach($tabs as $tab=>$title){
            echo $this->StartTab($tab);
                include('tabs/admin.'.$tab.'.php');
            echo $this->EndTab($tab);
        };
        echo $this->EndTabContent();
*/
        // time to add our error messages
        $errorMsg = str_replace(array("\n", "\r"), '', Antz::getError());

        if($errorMsg != '')
          echo '<script type="text/javascript" language="javascript">showErrorMsg(\''.$errorMsg.'\', \''.$this->config['root_url'].'\')</script>';
        $successMsg = str_replace(array("\n", "\r"), '', Antz::getSuccess());

        if($successMsg != '')
          echo '<script type="text/javascript" language="javascript">showSuccessMsg(\''.$successMsg.'\', \''.$this->config['root_url'].'\')</script>';
    }
}



function ProcessEmailTemplate($tpl, $params, $layoutTpl=''){
	if($layoutTpl == ''){
		$layoutTpl = 'layout.php';
	}
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
    foreach($params as $k=>$v){
    	$this->smarty->assign('IUsers_'.$k, $v);
    }
    $content = $this->smarty->fetch($dirname.'/email_templates/'.$tpl);
    $this->smarty->assign('IUsers_EmailContent', $content);
    return $this->smarty->fetch($dirname.'/email_templates/'.$layoutTpl);
}






function LoadConfig(){
    $DB = Antz::registry('db');
    global $gCms;
    // make sure we have been installed!
    if(!($config = $DB->fetchAll("SELECT * FROM {$this->config['db_prefix']}iusers_config"))) return;
    foreach($config as $k=>$v){
        $this->IUsers_Config[$v['k']] = $v['v'];
    };
}







function GetConfig($k){
    if(isset($this->IUsers_Config[$k])) return $this->IUsers_Config[$k];
    else if($this->ThrowConfigExceptions) throw new Exception($this->GetName().'->GetConfig was asked to find a non-existing key: '.$k);
    else return false;
}






function GetUrl($params, $id, $name, $action, $inline=true){
	$Antz = Antz::registry('Antz');
	return $Antz->GetUrl($params, $id, $name, $action, $inline);
}




function RedirectSuccess($url, $msg){
    $url .= '&m1_module_message='.urlencode($msg);
    Antz::redir($url);
}





function ReadEmailTemplate($name){
    if(!file_exists(dirname(__FILE__).'/email_templates/'.$name)){
        throw new Exception('Email template: modules/'.$this->GetName().'/email_templates/'.$name.' does not exist!');
        return '';
    }else{
        // get our specific template
        $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));
        ob_start();
        include($dirname.'/email_templates/'.$name);
        $msg = ob_get_contents();
        ob_end_clean();

        // get our layout template
        ob_start();
        include($dirname.'/email_templates/layout.php');
        $tpl = ob_get_contents();
        ob_end_clean();

        // insert our specific template to the layout template
        $tpl = str_replace(':|content|:', $msg, $tpl);

        return $tpl;
    }
}




/**
 *  INSTALL AND UNINSTALL METHODS
 */

function Install(){
    include('install/install.php');
}
function Uninstall(){
    include('install/uninstall.php');
}

function Upgrade(){
    $DB = Antz::registry('db');
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__FILE__));


    // add some new configuration options
    if($DB->countRows(cms_db_prefix().'iusers_config', "k = 'wrap_form_components'")==0){
        $dbParams = array(
            'k' => 'wrap_form_components',
            'v' => 1,
            'title' => 'Wrap form components in a div with class "component"?',
            'field_type' => 'boolean'
        );
        $DB->insert(cms_db_prefix().'iusers_config', $dbParams);
    }

    if($DB->countRows(cms_db_prefix().'iusers_config', "k = 'auto_forms'")==0){
        $dbParams = array(
            'k' => 'auto_forms',
            'v' => 1,
            'title' => 'Auto-generate forms without using templates?',
            'field_type' => 'boolean'
        );
        $DB->insert(cms_db_prefix().'iusers_config', $dbParams);
    }

    if($DB->countRows(cms_db_prefix().'iusers_config', "k = 'show_labels'")==0){
        $dbParams = array(
            'k' => 'show_labels',
            'v' => 1,
            'title' => 'Show labels in form components?',
            'field_type' => 'boolean'
        );
        $DB->insert(cms_db_prefix().'iusers_config', $dbParams);
    }


    if($DB->countRows(cms_db_prefix().'iusers_config', "k = 'register_show_fields'")==0){
        $dbParams = array(
            'k' => 'register_show_fields',
            'v' => '',
            'title' => 'Which fields to show on registration page?',
            'field_type' => 'boolean'
        );
        $DB->insert(cms_db_prefix().'iusers_config', $dbParams);
    }

    if($DB->countRows(cms_db_prefix().'iusers_config', "k = 'profile_show_fields'")==0){
        $dbParams = array(
            'k' => 'profile_show_fields',
            'v' => '',
            'title' => 'Which fields to show on profile page?',
            'field_type' => 'boolean'
        );
        $DB->insert(cms_db_prefix().'iusers_config', $dbParams);
    }

    if($DB->countRows(cms_db_prefix().'iusers_config', "k = 'email_login'")==0){
        $dbParams = array(
            'k' => 'email_login',
            'v' => 0,
            'title' => 'Login with email instead of username?',
            'field_type' => 'boolean'
        );
        $DB->insert(cms_db_prefix().'iusers_config', $dbParams);
    }


    // converting from storing aliases to ids
    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('login_url')."'");
    $dbParams = array('k'=>'login_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'login_url'");

    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('lost_password_url')."'");
    $dbParams = array('k'=>'lost_password_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'lost_password_url'");

    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('logout_url')."'");
    $dbParams = array('k'=>'logout_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'logout_url'");

    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('email_verification_url')."'");
    $dbParams = array('k'=>'email_verification_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'email_verification_url'");

    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('register_url')."'");
    $dbParams = array('k'=>'register_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'register_url'");

    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('profile_url')."'");
    $dbParams = array('k'=>'profile_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'profile_url'");

    $id = $DB->oneValue(cms_db_prefix().'content', 'content_id', "content_alias = '".$this->GetConfig('tnc_url')."'");
    $dbParams = array('k'=>'tnc_id', 'field_type'=>'page', 'v'=>$id);
    $DB->update(cms_db_prefix().'iusers_config', $dbParams, "k = 'tnc_url'");








    // remove change country until languages are supported
    $DB->delete(cms_db_prefix().'iusers_config', "k = 'change_country_url'");






}


function Restore($tstamp){
    $DB = Antz::registry('db');

    $tables = array(
        'iusers',
        'iusers_groups',
        'iusers_cities',
        'iusers_config',
        'iusers_countries',
        'iusers_to_groups',
        'iusers_pages_to_groups',
        'iusers_history'
    );

    $dirname = dirname(__FILE__);
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', $dirname);

    $folder = $dirname.'/backups/'.$tstamp;
    if(!is_dir($folder)) return false;

    foreach($tables as $k=>$v){
        // read file contents
        ob_start();
        include($folder.'/'.$v.'.sql');
        $sql = ob_get_contents();
        ob_end_clean();
        $sql = str_replace('prefix_', cms_db_prefix(), $sql);
        $DB->query($sql);
    };

    return true;

}

function Backup(){

    $DB = Antz::registry('db');

    $tables = array(
        'iusers',
        'iusers_groups',
        'iusers_cities',
        'iusers_config',
        'iusers_countries',
        'iusers_to_groups',
        'iusers_pages_to_groups',
        'iusers_history'
    );

    $dirname = dirname(__FILE__);
    $dirname = str_replace(DIRECTORY_SEPARATOR, '/', $dirname);

    $key = time();
    $folder = $dirname.'/backups/'.$key;

    mkdir($folder, 0777);

    $prefix = cms_db_prefix();

    // create the notice file
    $fh = fopen($folder.'/info.txt', 'w');
    $content = 'Backup created at '.date('H:i d M Y')."\n\nTables in backup: \n";
    foreach($tables as $k=>$v){
        $content .= $prefix.$v."\n";
    };
    fwrite($fh, $content);
    fclose($fh);

    // create the backup sql for each table
    foreach($tables as $k=>$v){
        $q = "SELECT * FROM {$prefix}{$v}";
        $rows = $DB->fetchAll($q);
        $sql = $this->GetSqlRow($v, $rows);
        file_put_contents($folder.'/'.$v.'.sql', $sql);
    };

}

function GetSqlRow($tablename, $rows){
    // get our keys
    $DB = Antz::registry('db');

    $keys = array();
    foreach($rows as $k=>$v){
        foreach($v as $key=>$value){
            $keys[] = $key;
        };
        break;
    };

    // get our values
    $values = array();
    foreach($rows as $k=>$v){
        $values[$k] = array();
        foreach($v as $key=>$value){
            $values[$k][] = $DB->escape($value);
        };
    };

    // create our field definition
    $sql = "INSERT INTO prefix_{$tablename} (`".implode('`, `', $keys)."`) VALUES ";
    foreach($values as $k=>$row){
        $sql .= "('".implode("', '", $row)."'),";
    };
    $sql .= ';';
    if(substr($sql, strlen($sql)-2) == ',;'){
        $sql = substr($sql, 0, strlen($sql)-2).';';
    };
    return $sql;
}




function AddPage($params, $title, $action){
    global $gCms;
    $userid = get_userid();
    $parent_id = -1;
    $contentops =& $gCms->GetContentOperations();
    $contentobj = $contentops->CreateNewContent('content');

  	$contentobj->SetOwner($userid);
  	$contentobj->SetCachable(1);
  	$contentobj->SetActive(1);
  	$contentobj->SetShowInMenu(0);
  	$contentobj->SetLastModifiedBy($userid);
  	$contentobj->SetPropertyValue('content_en', '<h1>'.$title.'</h1>'.'{cms_module module="'.$this->GetName().'" action="'.$action.'"}');
  	if ($parent_id!=-1) $contentobj->SetParentId($parent_id);
        else $contentobj->SetParentId(-1);

    $contentobj->FillParams($params);

    $error = $contentobj->ValidateData();

		if ($error === false){
  			$contentobj->Save();
  			global $gCms;
  			$contentops =& $gCms->GetContentOperations();
  			$contentops->SetAllHierarchyPositions();
  			audit($contentobj->Id(), $contentobj->Name(), 'Added Content by module '.$this->GetName());
    		$id = $contentobj->Id();
//                die('Inserted with id '.$id.': '.print_r($params, true));
                    return $id;
		};

//                die('Failed to insert page '.print_r($params, true));

		return false;
}





private function addHooksToCore(){

  global $gCms;

  $error = false;

  // check that we have permission to edit the files we need to hook into
  $filename = str_replace(DIRECTORY_SEPARATOR, '/', $this->config['root_path']).'/lib/classes/class.content.inc.php';
  if(!is_writeable($filename)){
      $error = true;
      Antz::addError('&bull;'.$filename);
  };
  $menufilename = str_replace(DIRECTORY_SEPARATOR, '/', $this->config['root_path']).'/modules/MenuManager/action.default.php';
  if(!is_writeable($menufilename)){
      $error = true;
      Antz::addError('&bull;'.$menufilename);
  };
  $contentfilename = str_replace(DIRECTORY_SEPARATOR, '/', $this->config['root_path']).'/lib/classes/contenttypes/Content.inc.php';
  if(!is_writeable($contentfilename)){
      $error = true;
      Antz::addError('&bull;'.$contentfilename);
  };
  if($error){
      // extremely rare is the circumstance we need to push an error onto the stack!
      Antz::addError('Installation requires write permissions to add hooks in some files');
      return false;
  };



  // add our hook to keep alias' sync'd
  $fc = file_get_contents($filename);
  $lines = explode("\n", $fc);
  $fileUpdated = false;
  $startLine = 0;
  $endLine = 0;
  foreach($lines as $lineNumber=>$line){
      $charsOnly = preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $line);
      if(strpos($charsOnly, 'functionDoReadyForEdit(')!==false){
          // we found our function definition
          if(strpos($charsOnly, '{') !== false) $startLine = $lineNumber+1;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $lines[$lineNumber+1]), '{') !== false) $startLine = $lineNumber+2;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $lines[$lineNumber+2]), '{') !== false) $startLine = $lineNumber+3;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $lines[$lineNumber+3]), '{') !== false) $startLine = $lineNumber+4;
          else die('Could not find the start of the function definition "DoReadyForEdit" in file '.$filename);

          $newLines = array(
              '    // start '.$this->GetName().' module installer at '.date('H:i d M Y'),
              '    global $gCms;',
              '    if(is_object($gCms->modules[\''.$this->GetName().'\'][\'object\'])){',
              '      $module = $gCms->modules[\''.$this->GetName().'\'];',
              '      if (($module[\'installed\'] && $module[\'active\']) && method_exists($module[\'object\'], \'ContentReadyForEdit\'))',
              '        $module[\'object\']->ContentReadyForEdit($this);',
              '    };',
              '    // end '.$this->GetName().' module installer at '.date('H:i d M Y')
          );

          foreach($newLines as $k=>$v){
              $newLineNumber = $startLine + $k;
              $lines = array_insert($lines, $newLineNumber, $v);
          };

          $newFc = implode("\n", $lines);

          // now we write the contents to the file
          $fh = fopen($filename, 'w');
          fwrite($fh, $newFc);
          fclose($fh);

          $fileUpdated = true;
      };
  };

  if(!$fileUpdated){
    Antz::addError('File '.$filename.' was not updated. This file
    requires the following hook inserted in the method ContentBase::DoReadyForEdit:<br />'.
    implode('<br />', $newLines));
    return false;
  }

  unset($newLines, $lines, $fc);

  // add our hook to hide non-permitted menu items
  $fc = file_get_contents($menufilename);
  $lines = explode("\n", $fc);
  $fileUpdated = false;
  $startLine = 0;
  $endLine = 0;
  foreach($lines as $lineNumber=>$line){
      $charsOnly = preg_replace('/[^a-zA-Z0-9_\-\(\)\{\$>]/', '', $line);
      if(strpos($charsOnly, 'if(count($nodelist)>0)')!==false){
          // we found our line
          if(strpos($charsOnly, '{') !== false) $startLine = $lineNumber+1;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $lines[$lineNumber+1]), '{') !== false) $startLine = $lineNumber+2;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $lines[$lineNumber+2]), '{') !== false) $startLine = $lineNumber+3;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $lines[$lineNumber+3]), '{') !== false) $startLine = $lineNumber+4;
          else die('Could not find the line we need to hook into: "if (count($nodelist) > 0)" in file '.$menufilename);

          $newLines = array(
              '    // start '.$this->GetName().' module installer at '.date('H:i d M Y'),
              '    if(is_object($gCms->modules[\''.$this->GetName().'\'][\'object\'])){',
              '      $module = $gCms->modules[\''.$this->GetName().'\'];',
              '      if (($module[\'installed\'] && $module[\'active\']) && method_exists($module[\'object\'], \'ContentReadyForEdit\'))',
              '          $nodelist = $gCms->modules[\''.$this->GetName().'\'][\'object\']->ParseMenu($nodelist);',
              '      };',
              '    // end '.$this->GetName().' module installer at '.date('H:i d M Y')
          );

          foreach($newLines as $k=>$v){
              $newLineNumber = $startLine + $k;
              $lines = array_insert($lines, $newLineNumber, $v);
          };

          $newFc = implode("\n", $lines);

          // now we write the contents to the file
          $fh = fopen($menufilename, 'w');
          fwrite($fh, $newFc);
          fclose($fh);

          $fileUpdated = true;
          break 1;
      };
  };

  if(!$fileUpdated){
    Antz::addError('File '.$menufilename.' was not updated. This file
    requires the following hook inserted to process the $nodelist variable just before it is assigned to $smarty:<br />'.
    implode('<br />', $newLines));
    return false;
  }



  unset($newLines, $lines, $fc);

  // add our hook to hide non-permitted menu items
  $fc = file_get_contents($contentfilename);
  $lines = explode("\n", $fc);
  $fileUpdated = false;
  $startLine = 0;
  $endLine = 0;
  foreach($lines as $lineNumber=>$line){
      $charsOnly = preg_replace('/[^a-zA-Z0-9_\-\(\)\{\}\$\[\]>;=\'"]/', '', $line);
      if(strpos($charsOnly, 'if($tab==0)')!==false){
          // we found our line
          if(strpos($charsOnly, '{') !== false) $startLine = $lineNumber+1;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{\}]/', '', $lines[$lineNumber+1]), '{') !== false) $startLine = $lineNumber+2;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{\}]/', '', $lines[$lineNumber+2]), '{') !== false) $startLine = $lineNumber+3;
          else if(strpos(preg_replace('/[^a-zA-Z0-9_\-\(\{\}]/', '', $lines[$lineNumber+3]), '{') !== false) $startLine = $lineNumber+4;
          else die('Could not find the line we need to hook into: "if (count($nodelist) > 0)" in file '.$contentfilename);

          $newLines = array(
              '    // start '.$this->GetName().' module installer at '.date('H:i d M Y'),
              '    if(array_key_exists(\'IUsers\', $gCms->modules) && method_exists($gCms->modules[\'IUsers\'][\'object\'], \'GetContentFields\')){',
              '        $extraFields = $gCms->modules[\'IUsers\'][\'object\']->GetContentFields($this);',
              '        if(!is_array($extraFields)) continue;',
              '        foreach($extraFields as $extraField){',
              '            if(!is_array($extraField) || count($extraField)!=2) continue;',
              '            $ret[] = $extraField;',
              '        };',
              '    };',
              '    // end '.$this->GetName().' module installer at '.date('H:i d M Y')
          );

          foreach($newLines as $k=>$v){
              $newLineNumber = $startLine + $k;
              $lines = array_insert($lines, $newLineNumber, $v);
          };

          $newFc = implode("\n", $lines);

          // now we write the contents to the file
          $fh = fopen($contentfilename, 'w');
          fwrite($fh, $newFc);
          fclose($fh);

          $fileUpdated = true;
          break 1;
      };
  };

  if(!$fileUpdated){
    Antz::addError('File '.$contentfilename.' was not updated. This file
    requires the following hook inserted to retrieve the form fields when adding and editing content:<br />'.
    implode('<br />', $newLines));
    return false;
  }


  return true;


}




















private function removeHooksFromCore(){



  global $gCms;



  // check that we have permission to edit the Content.inc.php file
  $filename = str_replace(DIRECTORY_SEPARATOR, '/', $gCms->config['root_path']).'/lib/classes/class.content.inc.php';
  if(!is_writeable($filename)){
      Antz::addError('Write permission is required for '.$filename);
        return false;
  };
  $menufilename = str_replace(DIRECTORY_SEPARATOR, '/', $gCms->config['root_path']).'/modules/MenuManager/action.default.php';
  if(!is_writeable($menufilename)){
      Antz::addError('Write permission is required for '.$menufilename);
    return false;
  };
  $contentfilename = str_replace(DIRECTORY_SEPARATOR, '/', $gCms->config['root_path']).'/lib/classes/contenttypes/Content.inc.php';
  if(!is_writeable($contentfilename)){
      Antz::addError('Write permission is required for '.$contentfilename);
    return false;
  };


  // remove our hook from Content.inc.php
  $fc = file_get_contents($filename);
  $fcChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fc);
  $nameChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $this->GetName());
  $numOccurrences = 0;
  $numIterations = 0;
  while($numIterations < 1 && strpos($fcChars, 'start'.$nameChars)!==false){
      $numIterations++;
      $lines = explode("\n", $fc);
      $fileUpdated = false;

      $startLine = false;
      $endLine = false;

      foreach($lines as $lineNumber=>$line){
          $charsOnly = preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $line);
          if(strpos($charsOnly, 'start'.$nameChars)!==false) $startLine = $lineNumber;
          if(strpos($charsOnly, 'end'.$nameChars)!==false) $endLine = $lineNumber;

          if($startLine !== false && $endLine !== false){
              // we have found a block that was inserted by the module
              foreach($lines as $k=>$v){
                  if($k >= $startLine && $k <= $endLine) unset($lines[$k]);
              };
              $lines = array_regenerate_keys($lines);
              $fh = fopen($filename, 'w');
              fwrite($fh, implode("\n", $lines));
              fclose($fh);
              $startLine = false;
              $endLine = false;
              $numOccurrences++;
              break 1;
          };
      };

      $fc = file_get_contents($filename);
      $fcChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fc);

  };// end while finding our name in the file


  unset($fc);

  // remove our hook from menu manager
  $fc = file_get_contents($menufilename);
  $fcChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fc);
  $nameChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $this->GetName());
  $numOccurrences = 0;
  $numIterations = 0;
  while($numIterations < 1 && strpos($fcChars, 'start'.$nameChars)!==false){
      $numIterations++;
      //echo 'searching '.$menufilename.'<br />'.highlight_string($fc, true).'<br />';
      $lines = explode("\n", $fc);
      $fileUpdated = false;

      $startLine = false;
      $endLine = false;

      foreach($lines as $lineNumber=>$line){
          $charsOnly = preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $line);
          if(strpos($charsOnly, 'start'.$nameChars)!==false) $startLine = $lineNumber;
          if(strpos($charsOnly, 'end'.$nameChars)!==false) $endLine = $lineNumber;

          if($startLine !== false && $endLine !== false){
              // we have found a block that was inserted by the module
              //echo 'stripping '.$menufilename.' from lines '.$startLine.' to '.$endLine.'<br />';
              foreach($lines as $k=>$v){
                  if($k >= $startLine && $k <= $endLine) unset($lines[$k]);
              };
              $lines = array_regenerate_keys($lines);
              $fh = fopen($menufilename, 'w');
              fwrite($fh, implode("\n", $lines));
              fclose($fh);
              $startLine = false;
              $endLine = false;
              $numOccurrences++;
          };
      };

      $fc = file_get_contents($menufilename);
      $fcChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fc);

  };// end while finding our name in the file





  unset($fc);

  // remove our hook from menu manager
  $fc = file_get_contents($contentfilename);
  $fcChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fc);
  $nameChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $this->GetName());
  $numOccurrences = 0;
  $numIterations = 0;
  while($numIterations < 1 && strpos($fcChars, 'start'.$nameChars)!==false){
      $numIterations++;
      //echo 'searching '.$contentfilename.'<br />'.highlight_string($fc, true).'<br />';
      $lines = explode("\n", $fc);
      $fileUpdated = false;

      $startLine = false;
      $endLine = false;

      foreach($lines as $lineNumber=>$line){
          $charsOnly = preg_replace('/[^a-zA-Z0-9_\-\(\{]/', '', $line);
          if(strpos($charsOnly, 'start'.$nameChars)!==false) $startLine = $lineNumber;
          if(strpos($charsOnly, 'end'.$nameChars)!==false) $endLine = $lineNumber;

          if($startLine !== false && $endLine !== false){
              // we have found a block that was inserted by the module
              //echo 'stripping '.$contentfilename.' from lines '.$startLine.' to '.$endLine.'<br />';
              foreach($lines as $k=>$v){
                  if($k >= $startLine && $k <= $endLine) unset($lines[$k]);
              };
              $lines = array_regenerate_keys($lines);
              $fh = fopen($contentfilename, 'w');
              fwrite($fh, implode("\n", $lines));
              fclose($fh);
              $startLine = false;
              $endLine = false;
              $numOccurrences++;
          };
      };

      $fc = file_get_contents($contentfilename);
      $fcChars = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fc);



  return true;



  };// end while finding our name in the file













}























}
?>
